using TFlex.Model.Model3D.Geometry;

namespace External3D
{
	// Local coordinate system
	//
	// Локальная система координат
	public class LCS
	{
		// Tolerance for various calculations
		//
		// Точность вычислений
		public const double Epsilon = 1.0e-6;

		// Origin of this coordinate system
		//
		// Начало системы координат
		protected Point3D m_origin = new Point3D(0.0, 0.0, 0.0);
		public Point3D O
		{
			get { return new Point3D(m_origin); }
			set { m_origin = new Point3D(value); }
		}

		// Direction of the X axis
		//
		// Ось X
		protected Direction m_xAxis = new Direction(1.0, 0.0, 0.0);
		public Direction X
		{
			get
			{
				return new Direction(m_xAxis);
			}

			set
			{
				m_xAxis = new Direction(value);
				Orthonormalize();
			}
		}

		// Direction of the Y axis
		//
		// Ось Y
		protected Direction m_yAxis = new Direction(0.0, 1.0, 0.0);
		public Direction Y
		{
			get
			{
				return new Direction(m_yAxis);
			}

			set
			{
				m_yAxis = new Direction(value);
				Orthonormalize();
			}
		}

		// Direction of the Z axis which is automatically updated in order to keep the coordinate system orthogonal
		//
		// Ось Z расчитывается автоматически как векторное произведение первых двух векторов
		protected Direction m_zAxis = new Direction(0.0, 0.0, 1.0);
		public Direction Z { get { return new Direction(m_zAxis); } }

		// Returns local coordinate system modified by the specified affine transformation
		//
		// Возвращает локальную систему координат, преобразованную указанной аффинной трансформацией
		public static LCS operator *(LCS lcs, AffineTransformation transformation)
		{
			LCS copy = new LCS();
			copy.m_origin = lcs.m_origin * transformation;
			copy.m_xAxis = lcs.m_xAxis * transformation;
			copy.m_yAxis = lcs.m_yAxis * transformation;
			copy.m_zAxis = lcs.m_zAxis * transformation;
			copy.Orthonormalize();

			return copy;
		}
		// Constructs a local coordinate system with default parameters
		//
		// Конструктор
		public LCS()
		{
		}

		// Constructs a local coordinate system with specified parameters
		//
		// Конструктор
		public LCS(Point3D origin, Direction xAxis, Direction yAxis)
		{
			O = origin;
			X = xAxis;
			Y = yAxis;
		}

		// Constructs a local coordinate system equal to another one
		//
		// Конструктор
		public LCS(LCS other) : this(other.m_origin, other.m_xAxis, other.m_yAxis)
		{
		}

		// Recalculates axes to make them orthogonal and unit-length
		//
		// Ортонормализация осей
		protected void Orthonormalize()
		{
			m_yAxis = m_xAxis.CrossProduct(m_yAxis);
			if (m_yAxis.Magnitude < Epsilon)
				m_yAxis = m_xAxis.MakeOrtho();

			m_xAxis = m_xAxis.NormalizedVector();
			m_yAxis = m_yAxis.CrossProduct(m_xAxis).NormalizedVector();
			m_zAxis = m_xAxis.CrossProduct(m_yAxis).NormalizedVector();
		}
	};
}
